﻿namespace Arms.Framework
{
    using Arms.Framework.Properties;
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;

    public static class DictionaryExtensions
    {
        /// <summary>
        /// Appends specified text to each value in this dictionary
        /// </summary>
        /// <param name="source"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static Dictionary<int, string> AppendToValue(this Dictionary<int, string> source, string text)
        {
            Dictionary<int, string> dictionary = new Dictionary<int, string>();

            foreach (KeyValuePair<int, string> kvp in source)
            {
                if (kvp.Key > -1)
                {
                    dictionary.Add(kvp.Key, kvp.Value + text);
                }
                else
                {
                    dictionary.Add(kvp.Key, kvp.Value);
                }
            }

            return dictionary;
        }
        /// <summary>
        /// Appends specified text to each value in this dictionary
        /// </summary>
        /// <typeparam name="TSource">Dictionary Key is a type</typeparam>
        /// <param name="source"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static Dictionary<TSource, string> AppendToValue<TSource>(this Dictionary<TSource, string> source, string text)
        {
            Dictionary<TSource, string> dictionary = new Dictionary<TSource, string>();

            foreach (KeyValuePair<TSource, string> kvp in source)
            {
                dictionary.Add(kvp.Key, kvp.Value + text);
            }

            return dictionary;
        }
        /// <summary>
        /// Copies the contents of this source to the destination. By default, the destination is not overridden.
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <returns></returns>
        public static void CopyTo<TSource, TTarget>(this IDictionary<TSource, TTarget> source, IDictionary<TSource, TTarget> destination)
        {
            source.CopyTo(destination, false);
        }
        /// <summary>
        /// Copies the contents of this source to the destination
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <param name="overwriteDestination"></param>
        public static void CopyTo<TSource, TTarget>(this IDictionary<TSource, TTarget> source, IDictionary<TSource, TTarget> destination, bool overwriteDestination)
        {
            for (int i = 0; i < source.Count; i++)
            {
                KeyValuePair<TSource, TTarget> kvp = source.ElementAt(i);

                if (!destination.ContainsKey(kvp.Key))
                {
                    destination.Add(kvp.Key, kvp.Value);
                }
                else
                {
                    if (overwriteDestination)
                    {
                        destination[kvp.Key] = kvp.Value;
                    }
                }
            }
        }
        /// <summary>
        /// Gets the value if this key exists. Otherwise, creates a new instance of the given type and saves it to the TempDataDictionary.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static TTarget GetOrDefault<TTarget>(this Dictionary<string, object> source, string key) where TTarget : new()
        {
            if (source.ContainsKey(key) && source[key] is TTarget)
            {
                return (TTarget)Convert.ChangeType(source[key], typeof(TTarget));
            }
            else
            {
                TTarget item = new TTarget();
                source[key] = item;

                return item;
            }
        }
        /// <summary>
        /// Gets the value if this key exists. Otherwise, creates a new instance of the given type and saves it to the TempDataDictionary.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetOrBlank(this Dictionary<int, string> source, int key)
        {
            if (source.ContainsKey(key))
            {
                return source[key];
            }
            else
            {
                return string.Empty;
            }
        }
        /// <summary>
        /// Fills this IDictionary with the contents from a NameValueCollection
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <param name="collection"></param>
        public static void PopulateFrom<TSource, TTarget>(this IDictionary<TSource, TTarget> source, NameValueCollection collection)
        {
            foreach (string key in collection.Keys)
            {
                source[(TSource)Convert.ChangeType(key, typeof(TSource))] = (TTarget)Convert.ChangeType(collection[key], typeof(TTarget));
            }
        }
        /// <summary>
        /// Fills this IDictionary with the contents from another IDictionary
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <param name="collection"></param>
        public static void PopulateFrom<TSource, TTarget>(this IDictionary<TSource, TTarget> source, IDictionary<TSource, TTarget> collection)
        {
            foreach (TSource key in collection.Keys)
            {
                source[key] = collection[key];
            }
        }
        /// <summary>
        /// Fills this IDictionary with contents from an unknown object collection
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <param name="collection"></param>
        public static void PopulateFrom<TSource, TTarget>(this IDictionary<TSource, TTarget> source, object collection)
        {
            if (collection != null)
            {
                if (collection is NameValueCollection)
                {
                    source.PopulateFrom(collection as NameValueCollection);
                }
                else if (collection is IDictionary<TSource, TTarget>)
                {
                    source.PopulateFrom(collection as IDictionary<TSource, TTarget>);
                }
                else
                {
                    foreach (PropertyValue property in collection.GetProperties())
                    {
                        source[(TSource)Convert.ChangeType(property.Name, typeof(TSource))] = (TTarget)Convert.ChangeType(property.Value, typeof(TTarget));
                    }
                }
            }
        }
        /// <summary>
        /// Inserts a new KeyValuePair into the 0th position of this dictionary.
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static Dictionary<TSource, string> PrependToValue<TSource>(this Dictionary<TSource, string> source, string text)
        {
            Dictionary<TSource, string> dictionary = new Dictionary<TSource, string>();

            foreach (KeyValuePair<TSource, string> kvp in source)
            {
                dictionary.Add(kvp.Key, text + kvp.Value);
            }

            return dictionary;
        }
        /// <summary>
        /// Inserts a new KeyValuePair into the 0th position of this dictionary.
        /// </summary>
        /// <typeparam name="TSource">Generic type</typeparam>
        /// <typeparam name="TTarget">Generic type</typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Dictionary<TSource, TTarget> PrependValue<TSource, TTarget>(this Dictionary<TSource, TTarget> source, TSource key, TTarget value)
        {
            if (!source.ContainsKey(key))
            {
                Dictionary<TSource, TTarget> newDictionary = new Dictionary<TSource, TTarget>();
                newDictionary.Add(key, value);
                foreach (KeyValuePair<TSource, TTarget> kvp in source)
                {
                    newDictionary.Add(kvp.Key, kvp.Value);
                }
                return newDictionary;
            }
            else
            {
                return source;
            }
        }
        /// <summary>
        /// Updates the value of a given key for this dictionary
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns>Returns false if the key is not found.</returns>
        public static bool Update<TSource, TTarget>(this Dictionary<TSource, TTarget> source, TSource key, TTarget value)
        {
            if (source.ContainsKey(key))
            {
                source[key] = value;

                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Updates the value of a given key for this dictionary. If the key is not found, creates a new key
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TTarget"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void Upsert<TSource, TTarget>(this Dictionary<TSource, TTarget> source, TSource key, TTarget value)
        {
            if (source.ContainsKey(key))
            {
                source[key] = value;
            }
            else
            {
                source.Add(key, value);
            }
        }
    }
}
